package se.robertfoss.ChanImageBrowser.Fetcher;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Bundle;
import android.os.Message;
import android.util.Log;
import se.robertfoss.ChanImageBrowser.ImageHandler;
import se.robertfoss.ChanImageBrowser.Viewer;

public class ImageFetcher extends Thread {
	
	public static final int IS_PAUSED = -1;
	public static final int IS_UNINITIATED = -2;

	private FetcherManager manager;
	private ImageHandler imageHandler;
	private boolean isDone;
	private boolean isPaused;
	private int downloadProgress = IS_UNINITIATED;
	private final static int THREAD_SLEEP_TIME = 1000;


	ImageFetcher(FetcherManager manager, ImageHandler imageHandler) {
		this.manager = manager;
		this.imageHandler = imageHandler;
		isDone = false;
		isPaused = false;
	}

	public void done() {
		isDone = true;
	}
	
	public void pause(Boolean isPaused){
		this.isPaused = isPaused;
	}
	
	public boolean isPaused(){
		return isPaused;
	}

	public void run() {
		isDone = false;
		String inputUrl;
		while (!isDone) {
			
			while (manager.getNbrImagesToDownload() > 0 && 
					(inputUrl = manager.getNextImageName()) != null 
					&& !isPaused
					&& !isDone) {
				Log.d("ImageFetcher", "Images left to download: " + manager.getNbrImagesToDownload());
				Log.d("ImageFetcher", super.getName() + " is fetching picture  -  " + inputUrl);
				String[] fileName = inputUrl.split("/");

				try {
					File pic = new File(Viewer.tempDir, fileName[fileName.length - 1]);
					download(inputUrl, pic);
					displayImage(pic);
					downloadProgress = 0;
				} catch (FileNotFoundException e) {
					Log.d("ImageFetcher", "File not found - " + fileName[fileName.length - 1]);
					e.printStackTrace();
				}
				catch (DownloadIOException e) {
					downloadProgress = IS_UNINITIATED;
					Log.d("ImageFetcher", "Unable to download image - " + inputUrl);
					e.printStackTrace();
				} catch (StorageIOException e) {
					Log.d("ImageFetcher", "Unable to save downloaded image - " + inputUrl);
					e.printStackTrace();
				}	catch (IOException e) {
					Log.d("ImageFetcher", "Unable to fetch image - " + inputUrl);
					e.printStackTrace();
				}

				inputUrl = manager.getNextImageName();
			}
			
			/* Wait for new data or to be unpaused */
			try {
				Thread.sleep(THREAD_SLEEP_TIME);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public int getProgress() {
		if (isPaused) {
			return IS_PAUSED;
		} else {
			return downloadProgress;
		}
	}
	
	private void download(String inputUrl, File outputFile) throws DownloadIOException, FileNotFoundException, IOException,
																	 StorageIOException {
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        try {
        	URL url = new URL(inputUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();
        } catch (IOException e) {
        	cleanup(output, input, connection);
        	throw new DownloadIOException(e.getMessage());
        }

        /* Expect HTTP 200 OK, so we don't mistakenly save error report instead of the file */
        if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
        	throw new DownloadIOException();
        }

        /* This will be useful to display download percentage might be -1: server did not report the length */
        int fileLength = connection.getContentLength();

        try {
        	output = new FileOutputStream(outputFile);
        } catch (FileNotFoundException e) {
        	throw e;
        }

        byte data[] = new byte[4096];
        long total = 0;
        int count;
        try {
        	input = connection.getInputStream();
        	count = input.read(data);
        } catch (IOException e) {
        	cleanup(output, input, connection);
        	throw new DownloadIOException(e.getMessage());
        }
        
        while (count != -1) {
            total += count;
            /* Publish the progress iff total length is known */
            if (fileLength > 0) {
                downloadProgress = ((int) (total * 100 / fileLength));
            }
            try {
            	output.write(data, 0, count);
            } catch (IOException e) {
            	cleanup(output, input, connection);
            	throw new StorageIOException(e.getMessage());
            }
            try {
            	count = input.read(data);
            } catch (IOException e) {
            	cleanup(output, input, connection);
            	throw new DownloadIOException(e.getMessage());
            }
        }
        cleanup(output, input, connection);
	}
	
	private void cleanup(OutputStream output, InputStream input, HttpURLConnection connection) {
        try {
            if (output != null)
                output.close();
        } catch (IOException ignored) { }
        try {
            if (input != null)
                input.close();
        } catch (IOException ignored) { }

        if (connection != null)
            connection.disconnect();
	}
	
	private void displayImage(File file) throws IOException {
		Log.d("ImageFetcher", super.getName() + " is adding downloaded a picture: " + file.toString());
		
		/* Test if the file is a legitimate image and then add it */
		Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(file.toString(), options);
//		if (options.outHeight != -1) {
//			throw new IOException("A downloaded file is not an image: " + file.toString());
//		}
		
		Message msg = imageHandler.obtainMessage();
		Bundle bundle = new Bundle();
		bundle.putString("filename", file.toString());
		msg.setData(bundle);
		imageHandler.sendMessage(msg);
		
	}
	
	private class DownloadIOException extends IOException {
		public DownloadIOException() {
			super();
		}
		public DownloadIOException(String msg) {
			super(msg);
		}
	}
	
	private class StorageIOException extends IOException {
		public StorageIOException() {
			super();
		}
		public StorageIOException(String msg) {
			super(msg);
		}
	}
}
